﻿Imports System.IO.IsolatedStorage
Imports Runa.Common.Helper
Imports Runa.Foundation.IO
Imports System.IO
Imports System.Text

#If NETFX_CORE Then
Imports System.IO.Compression
Imports Windows.Storage.Compression
#Else
Imports ICSharpCode.SharpZipLib
Imports ICSharpCode.SharpZipLib.Zip
#End If

#If WINDOWS_PHONE Then
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
#ElseIf WINDOWS Then
Imports System.Drawing
#End If

Namespace Global.Runa.Core.GamePackage

    Public Class RunaGamePackage
        Inherits GamePackageBase

        ''' <summary>
        ''' By default, our package should be strored in the IsolatedStorage.
        ''' </summary>
        ''' <param name="gamePackageFileName">The file name of the package.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal gamePackageFileName As String)
            MyBase.New(gamePackageFileName)
        End Sub

        ''' <summary>
        ''' By default, our package should be strored in the IsolatedStorage.
        ''' But we can also store in other places like file system.
        ''' </summary>
        ''' <param name="gamePackageFileName"></param>
        ''' <param name="physicalStorage"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal gamePackageFileName As String, ByVal physicalStorage As GameDirectory)
            MyBase.New(gamePackageFileName, physicalStorage)
        End Sub

        ''' <summary>
        ''' Save and extract a package from a stream.
        ''' </summary>
        ''' <param name="gameName"></param>
        ''' <param name="packageStream"></param>
        ''' <param name="physicalStorage"></param>
        ''' <remarks>
        ''' Make sure that the stream is a non-network stream to gain better performance and stability.
        ''' </remarks>
        Public Sub New(ByVal gameName As String, ByVal packageStream As Stream, Optional ByVal physicalStorage As GameDirectory = Nothing)
            MyBase.New(gameName, packageStream, physicalStorage)
        End Sub

        Public Overrides Sub AnalyzeConfigurationFile()
            If Me.PhysicalStorage.DirectoryExists(Me.GameContentRoot) Then
                Using fs = Me.PhysicalStorage.OpenFile(Path.Combine(Me.GameContentRoot, "Configuration.xml"), Runa.Foundation.IO.FileMode.Open)
                    Dim configXml = XElement.Load(fs)
                    For Each element In configXml.Elements()
                        Select Case element.Name
                            Case "Name"
                                Me.Name = element.Value
                            Case "Author"
                                Me.Author = element.Value
#If (Windows And (Not NETFX_CORE)) Then
                            Case "WindowHeight"
                                Me.WindowHeight = CInt(element.Value)
                            Case "WindowWidth"
                                Me.WindowWidth = CInt(element.Value)
#End If
#If WINDOWS_PHONE Then
                            Case "Orientation"
                                Me.Orientation = element.Value
#End If
                            Case "Fps"
                                Me.Fps = CInt(element.Value)
                            Case "Image"
#If WINDOWS_PHONE Then
                                Me.Image = New BitmapImage()
                                Me.m_imageStream = Me.PhysicalStorage.OpenFile(Path.Combine(Me.GameContentRoot, element.Value), Runa.Foundation.IO.FileMode.Open)
                                Me.Image.SetSource(Me.m_imageStream)
#ElseIf WINDOWS Then
#If Not NETFX_CORE Then
                                Me.m_imageStream = Me.PhysicalStorage.OpenFile(Path.Combine(Me.GameContentRoot, element.Value), Runa.Foundation.IO.FileMode.Open)
                                Me.Image = New Bitmap(Me.m_imageStream)
#Else
                                Me.m_imageStream = Me.PhysicalStorage.OpenFile(Path.Combine(Me.GameContentRoot, element.Value), System.IO.FileMode.Open)
                                Using ms As New MemoryStream()
                                    Me.m_imageStream.CopyTo(ms)
                                    Me.Image = ms.ToArray()
                                End Using
#End If
#End If
#If WINDOWS Then
                            Case "MouseSensitive"
                                Me.MouseSensitive = CInt(element.Value)
#If Not NETFX_CORE Then
                            Case "IsFullScreen"
                                If Boolean.TryParse(element.Value, Me.IsFullScreen) = False Then
                                    Me.IsFullScreen = False
                                End If
#End If
#End If
                            Case "GPUAccelerationEnabled"
                                If Boolean.TryParse(element.Value, Me.GPUAccelerationEnabled) = False Then
                                    Me.GPUAccelerationEnabled = False
                                End If
                            Case Else
                                Continue For
                        End Select
                    Next
                    fs.Close()
                End Using
            End If
        End Sub

        Public Overrides Function ExtractFromStream(ByVal packageStream As Stream) As Boolean
            Try
                If Me.PhysicalStorage.DirectoryExists(Me.GameContentRoot) Then
                    Me.PhysicalStorage.DeleteDirectory(Me.GameContentRoot, True)
                End If
                Me.PhysicalStorage.CreateDirectory(Me.GameContentRoot)

#If WINDOWS_PHONE Then
                ZipConstants.DefaultCodePage = DBCSEncoding.GetDBCSEncoding("gb2312")
'#ElseIf Windows And (Not NETFX_CORE) Then
'                ZipConstants.DefaultCodePage = 936 ' Encoding.Default.CodePage
#End If

                ' ToDo: Add password support.
#If NETFX_CORE Then
                Using zipArch As New ZipArchive(packageStream, ZipArchiveMode.Read)
                    Dim currentPath = Me.GameContentRoot
                    For Each entry In zipArch.Entries
                        Using Input = entry.Open()
                            If entry.Name = "" And entry.FullName.EndsWith("/") Then
                                Continue For
                            Else
                                Dim fp = GetNomalizedPath(Path.Combine(Me.GameContentRoot, entry.FullName)).Replace("/", "\")
                                Using isolatedFileStream = Me.PhysicalStorage.OpenFile(fp, Runa.Foundation.IO.FileMode.OpenOrCreate)
                                    Input.CopyTo(isolatedFileStream)
                                    isolatedFileStream.Flush()
                                    isolatedFileStream.Dispose()
                                End Using
                            End If
                        End Using
                    Next
                End Using
                Return True
#Else
                Using zipStream As New ZipInputStream(packageStream)
                    Using reader = New BinaryReader(zipStream)
                        Dim theEntry As ZipEntry = Nothing
                        While (Function()
                                   theEntry = zipStream.GetNextEntry()
                                   Return theEntry IsNot Nothing
                               End Function)()
                            Dim fileName = theEntry.Name
                            If fileName <> String.Empty Then
                                Dim path = GetNomalizedPath(System.IO.Path.Combine(Me.GameContentRoot, fileName)).Replace("/", "\")
                                If (Not theEntry.IsFile) Or _
                                    (Not theEntry.IsCompressionMethodSupported()) Or _
                                    (Not theEntry.CanDecompress) Then
                                    Me.PhysicalStorage.CreateDirectory(path)
                                Else
                                    Using isolatedFileStream = Me.PhysicalStorage.OpenFile(path, Runa.Foundation.IO.FileMode.OpenOrCreate)
                                        Using writer = New BinaryWriter(isolatedFileStream)
                                            Dim size = 2048
                                            Dim data(2048) As Byte
                                            While True
                                                size = reader.Read(data, 0, data.Length)
                                                If size > 0 Then
                                                    writer.Write(data, 0, size)
                                                Else
                                                    Exit While
                                                End If
                                            End While
                                            writer.Close()
                                        End Using
                                        isolatedFileStream.Close()
                                    End Using
                                End If
                            End If
                        End While
                        reader.Close()
                    End Using
                    zipStream.Close()
                End Using
                Return True
#End If
            Catch ex As Exception
                Throw ex
                Return False
            End Try
        End Function

    End Class

End Namespace